#include "ring_buffer.h"
#include "main.h" 

void ring_buffer_init(RingBuffer_t *rb)
{
    rb->head = 0;
    rb->tail = 0;
    rb->count = 0;
}

bool ring_buffer_push(RingBuffer_t *rb, uint8_t data)
{
    uint32_t primask = __get_PRIMASK();
    __disable_irq();  
    
    if (rb->count >= RING_BUFFER_SIZE) {
        __set_PRIMASK(primask);  
        return false; 
    }
    
    rb->buffer[rb->head] = data;
    rb->head = (rb->head + 1) & (RING_BUFFER_SIZE - 1); 
    rb->count++;
    
    __set_PRIMASK(primask);  
    return true;
}

bool ring_buffer_pop(RingBuffer_t *rb, uint8_t *data)
{
    uint32_t primask = __get_PRIMASK();
    __disable_irq(); 
    if (rb->count == 0) {
        __set_PRIMASK(primask);  
        return false; 
    }
    
    *data = rb->buffer[rb->tail];
    rb->tail = (rb->tail + 1) & (RING_BUFFER_SIZE - 1);
    rb->count--;
    
    __set_PRIMASK(primask);  
    return true;
}

bool ring_buffer_push_array(RingBuffer_t *rb, const uint8_t *data, uint16_t len)
{
    uint32_t primask = __get_PRIMASK();
    __disable_irq();
    
    if (ring_buffer_free_space(rb) < len) {
        __set_PRIMASK(primask);
        return false;
    }
    
    for (uint16_t i = 0; i < len; i++) {
        rb->buffer[rb->head] = data[i];
        rb->head = (rb->head + 1) & (RING_BUFFER_SIZE - 1);
    }
    rb->count += len;
    
    __set_PRIMASK(primask);
    return true;
}

bool ring_buffer_pop_array(RingBuffer_t *rb, uint8_t *data, uint16_t len)
{
    uint32_t primask = __get_PRIMASK();
    __disable_irq();
    
    if (rb->count < len) {
        __set_PRIMASK(primask);
        return false;
    }
    
    for (uint16_t i = 0; i < len; i++) {
        data[i] = rb->buffer[rb->tail];
        rb->tail = (rb->tail + 1) & (RING_BUFFER_SIZE - 1);
    }
    rb->count -= len;
    
    __set_PRIMASK(primask);
    return true;
}

uint16_t ring_buffer_available(RingBuffer_t *rb)
{
    uint32_t primask = __get_PRIMASK();
    __disable_irq();
    uint16_t count = rb->count;
    __set_PRIMASK(primask);
    return count;
}

uint16_t ring_buffer_free_space(RingBuffer_t *rb)
{
    return RING_BUFFER_SIZE - ring_buffer_available(rb);
}

bool ring_buffer_is_empty(RingBuffer_t *rb)
{
    return (ring_buffer_available(rb) == 0);
}

bool ring_buffer_is_full(RingBuffer_t *rb)
{
    return (ring_buffer_available(rb) == RING_BUFFER_SIZE);
}

void ring_buffer_clear(RingBuffer_t *rb)
{
    uint32_t primask = __get_PRIMASK();
    __disable_irq();
    rb->head = 0;
    rb->tail = 0;
    rb->count = 0;
    __set_PRIMASK(primask);
}

bool ring_buffer_peek(RingBuffer_t *rb, uint8_t *data, uint16_t offset)
{
    uint32_t primask = __get_PRIMASK();
    __disable_irq();
    
    if (offset >= rb->count) {
        __set_PRIMASK(primask);
        return false;
    }
    
    uint16_t index = (rb->tail + offset) & (RING_BUFFER_SIZE - 1);
    *data = rb->buffer[index];
    
    __set_PRIMASK(primask);
    return true;
}